BigQueryの列暗号化で使われる鍵セットのローテーションを試してみる
はじめに
データアナリティクス事業本部のkobayashiです。
BigQueryのCloud KMSによる列レベルの暗号化で使う鍵セットのローテーションを試してみたのでまとめます。
Cloud KMSでラップされた鍵セットのローテーション
鍵セットは列レベルの暗号化を行う際に使われるものでCloud KMSキーリング(関連するキーをグループ化するコンテナ)、暗号鍵(実際のデータ暗号化に使用)、および鍵バージョン(同じ暗号鍵の異なるバージョン)で構成されます。
鍵セットは主に以下のような確定的・非確定的暗号化関数で使用します。
鍵セットを定期的にローテーションすることでデータセキュリティを強化するたことができ、同じ鍵が長期間使用されることによるリスクを軽減し潜在的な脆弱性や攻撃の可能性を減らしたり、鍵が漏洩した場合でもその影響を特定の期間のデータに限定することができ全体的なデータセキュリティを維持できます。
今回はこの鍵セットのローテーションを以下のSQLで試してみます。
前提条件として暗号化は確定的暗号化関数を使います。
DECLARE SAMPLE_STR STRING DEFAULT '暗号化前の文字列';
DECLARE KMS_KEY STRING DEFAULT 'gcp-kms://projects/{プロジェクトID}/locations/asia-northeast1/keyRings/bq_col_encrypt_keyring/cryptoKeys/bq_col_encrypt_key';
DECLARE KEY_SET BYTES DEFAULT (SELECT KEYS.NEW_WRAPPED_KEYSET(KMS_KEY, 'DETERMINISTIC_AEAD_AES_SIV_CMAC_256'));
DECLARE NEW_KEY_SET BYTES DEFAULT (SELECT KEYS.ROTATE_WRAPPED_KEYSET(KMS_KEY, KEY_SET,
'DETERMINISTIC_AEAD_AES_SIV_CMAC_256'));
DECLARE NEW_NEW_KEY_SET BYTES DEFAULT (SELECT KEYS.ROTATE_WRAPPED_KEYSET(KMS_KEY, NEW_KEY_SET,
'DETERMINISTIC_AEAD_AES_SIV_CMAC_256'));
DECLARE ENC_SAMPLE_STR BYTES DEFAULT (SELECT DETERMINISTIC_ENCRYPT(KEYS.KEYSET_CHAIN(KMS_KEY, KEY_SET), SAMPLE_STR,
''));
SELECT 'KEY_SET', DETERMINISTIC_DECRYPT_STRING(KEYS.KEYSET_CHAIN(KMS_KEY, KEY_SET), ENC_SAMPLE_STR, '')
UNION ALL
SELECT 'NEW_KEY_SET', DETERMINISTIC_DECRYPT_STRING(KEYS.KEYSET_CHAIN(KMS_KEY, NEW_KEY_SET), ENC_SAMPLE_STR, '')
UNION ALL
SELECT 'NEW_NEW_KEY_SET', DETERMINISTIC_DECRYPT_STRING(KEYS.KEYSET_CHAIN(KMS_KEY, NEW_NEW_KEY_SET), ENC_SAMPLE_STR, '');
このSQLを細かく見ていきます。
DECLARE SAMPLE_STR STRING DEFAULT '暗号化前の文字列';
DECLARE KMS_KEY STRING DEFAULT 'gcp-kms://projects/{プロジェクトID}/locations/asia-northeast1/keyRings/bq_col_encrypt_keyring/cryptoKeys/bq_col_encrypt_key';
はじめに暗号化対象の文字列をSAMPLE_STR
として定義しています。また合わせてKMS_KEY
も定義しています。
DECLARE KEY_SET BYTES DEFAULT (SELECT KEYS.NEW_WRAPPED_KEYSET(KMS_KEY, 'DETERMINISTIC_AEAD_AES_SIV_CMAC_256'));
DECLARE NEW_KEY_SET BYTES DEFAULT (SELECT KEYS.ROTATE_WRAPPED_KEYSET(KMS_KEY, KEY_SET,
'DETERMINISTIC_AEAD_AES_SIV_CMAC_256'));
DECLARE NEW_NEW_KEY_SET BYTES DEFAULT (SELECT KEYS.ROTATE_WRAPPED_KEYSET(KMS_KEY, NEW_KEY_SET,
'DETERMINISTIC_AEAD_AES_SIV_CMAC_256'));
次に鍵セットを定義しています。確定的暗号化を行っているので鍵セットの型はDETERMINISTIC_AEAD_AES_SIV_CMAC_256
を指定しています。KEY_SET
で最初のCloud KMS でラップされた鍵セットを作成し、NEW_KEY_SET
でKEY_SET
をローテーションし、更にNEW_NEW_KEY_SET
でNEW_KEY_SET
をローテーションしています。
KEY_SET
: 最初のCloud KMS でラップされた鍵セットNEW_KEY_SET
:KEY_SET
をローテーションNEW_NEW_KEY_SET
:NEW_KEY_SET
をローテーション
DECLARE ENC_SAMPLE_STR BYTES DEFAULT (SELECT DETERMINISTIC_ENCRYPT(KEYS.KEYSET_CHAIN(KMS_KEY, KEY_SET), SAMPLE_STR,
次に最初に作成した鍵セットKEY_SET
を使ってSAMPLE_STR
を暗号化してENC_SAMPLE_STR
に設定しています。
SELECT 'KEY_SET', DETERMINISTIC_DECRYPT_STRING(KEYS.KEYSET_CHAIN(KMS_KEY, KEY_SET), ENC_SAMPLE_STR, '')
UNION ALL
SELECT 'NEW_KEY_SET', DETERMINISTIC_DECRYPT_STRING(KEYS.KEYSET_CHAIN(KMS_KEY, NEW_KEY_SET), ENC_SAMPLE_STR, '')
UNION ALL
SELECT 'NEW_NEW_KEY_SET', DETERMINISTIC_DECRYPT_STRING(KEYS.KEYSET_CHAIN(KMS_KEY, NEW_NEW_KEY_SET), ENC_SAMPLE_STR, '');
最後に暗号化されているENC_SAMPLE_STR
をKEY_SET
、NEW_KEY_SET
、NEW_NEW_KEY_SET
で復号化しています。全体を実行すると以下が返ってきてローテーションされた鍵セットでも問題なく復号化できることがわかります。
f0_ | f1_ |
---|---|
KEY_SET | 暗号化前の文字列 |
NEW_KEY_SET | 暗号化前の文字列 |
NEW_NEW_KEY_SET | 暗号化前の文字列 |
ローテーションする前の鍵セットでの復号化
ではこのSQLのうち暗号化する箇所で一度ローテーションされた鍵セットを使うように変更して実行してみます。
DECLARE ENC_SAMPLE_STR BYTES DEFAULT (SELECT DETERMINISTIC_ENCRYPT(KEYS.KEYSET_CHAIN(KMS_KEY, KEY_SET), SAMPLE_STR,
↓
DECLARE ENC_SAMPLE_STR BYTES DEFAULT (SELECT DETERMINISTIC_ENCRYPT(KEYS.KEYSET_CHAIN(KMS_KEY, NEW_KEY_SET), SAMPLE_STR,
Query error: DETERMINISTIC_DECRYPT_STRING failed: decryption failed; Error in DETERMINISTIC_DECRYPT_STRING (KEYS.KEYSET_CHAIN(\"gcp-kms://projects/{プロジェクトID}/locations/asia-northeast1/keyRings/bq_col_encrypt_keyring/cryptoKeys/bq_col_encrypt_key\", FIRST_LEVEL_KEYSET), b'\\001\\337\\264\\377\\307\\012\\144\\204\\077\\012\\053\\331\\070\\246\\116\\317\\274\\057\\363\\011\\331\\005\\064\\223\\051\\114\\154\\211\\351\\371\\106\\130\\362\\073\\166\\237\\210\\250\\224\\303\\220\\150\\307\\124\\105, ); error in DETERMINISTIC_DECRYPT_STRING expression at [12:5]
当然、ローテーションした鍵セットで暗号化を行っているのでローテーション前の鍵セットでは復号化ができないためエラーとなりました。
ただ当然ローテーションした鍵セットを更にローテーションしても復号化は問題なくできますので以下の様にコメントアウトして実行すれば問題なくクエリの実行は成功します。
BEGIN
DECLARE SAMPLE_STR STRING DEFAULT '暗号化前の文字列';
DECLARE KMS_KEY STRING DEFAULT 'gcp-kms://projects/{プロジェクトID}/locations/asia-northeast1/keyRings/bq_col_encrypt_keyring/cryptoKeys/bq_col_encrypt_key';
DECLARE KEY_SET BYTES DEFAULT (SELECT KEYS.NEW_WRAPPED_KEYSET(KMS_KEY, 'DETERMINISTIC_AEAD_AES_SIV_CMAC_256'));
DECLARE NEW_KEY_SET BYTES DEFAULT (SELECT KEYS.ROTATE_WRAPPED_KEYSET(KMS_KEY, KEY_SET,
'DETERMINISTIC_AEAD_AES_SIV_CMAC_256'));
DECLARE NEW_NEW_KEY_SET BYTES DEFAULT (SELECT KEYS.ROTATE_WRAPPED_KEYSET(KMS_KEY, NEW_KEY_SET,
'DETERMINISTIC_AEAD_AES_SIV_CMAC_256'));
DECLARE ENC_SAMPLE_STR BYTES DEFAULT (SELECT DETERMINISTIC_ENCRYPT(KEYS.KEYSET_CHAIN(KMS_KEY, NEW_KEY_SET), SAMPLE_STR,
''));
-- SELECT 'KEY_SET', DETERMINISTIC_DECRYPT_STRING(KEYS.KEYSET_CHAIN(KMS_KEY, KEY_SET), ENC_SAMPLE_STR, '')
-- UNION ALL
SELECT 'NEW_KEY_SET', DETERMINISTIC_DECRYPT_STRING(KEYS.KEYSET_CHAIN(KMS_KEY, NEW_KEY_SET), ENC_SAMPLE_STR, '')
UNION ALL
SELECT 'NEW_NEW_KEY_SET', DETERMINISTIC_DECRYPT_STRING(KEYS.KEYSET_CHAIN(KMS_KEY, NEW_NEW_KEY_SET), ENC_SAMPLE_STR, '');
END;
f0_ | f1_ |
---|---|
NEW_KEY_SET | 暗号化前の文字列 |
NEW_NEW_KEY_SET | 暗号化前の文字列 |
まとめ
BigQueryのCloud KMSによる列レベルの暗号化で使う鍵セットのローテーションを試してみました。鍵セットの定期的なローテーションはデータセキュリティを強化するための重要な手段になるので、列レベルの暗号化を行った際は適切なローテーション戦略を立てることが重要です。
最後まで読んで頂いてありがとうございました。